<!-- Tiny Editor 富文本编辑器 -->
<template>
  <div class="container">
    <div class="editor-container">
      <!-- 目录区域 -->
      <div class="directory-content">
        <div id="outline" ref="headerListRef" @click="asClick">
          <h5>
            目录
          </h5>
        </div>
      </div>
      <!-- 编辑器主体 -->
      <div class="editor-main">
        <div ref="editorRef"></div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue'
import FluentEditor from '@opentiny/fluent-editor'
import 'quill-header-list/dist/index.css'
import HeaderList from 'quill-header-list'
import { uploadFile } from '@/apis/system'

// 定义组件名称
defineOptions({ name: 'NoticeEditor' })

// 定义props和emit
const props = withDefaults(defineProps<{
  modelValue: string
  maxLength?: number
}>(), {
  maxLength: 2000,
})
const emit = defineEmits<{
  'update:modelValue': [value: string]
  'ready': [editor: any]
  'change': [value: string]
}>()
// 目录列表
const headerListRef = ref<HTMLElement>()
// 编辑器实例
let editorInstance: any = null

// 编辑器容器ref引用
const editorRef = ref<HTMLElement | null>(null)

// 内部状态，用于避免无限循环更新
const internalValue = ref(props.modelValue)

// 处理粘贴事件
const handlePaste = (node: any, delta: any) => {
  // 这里可以实现自定义的粘贴处理逻辑
  return delta
}
// 根据目录中的 id 获取标题并跳转
const asClick = (e: any) => {
  const dataId = e.target.dataset.id
  if (dataId) {
    // 查找编辑器中对应的元素并滚动到对应位置
    const targetElement = editorRef.value?.querySelector(`[id="${dataId}"]`) as HTMLElement
    if (targetElement) {
      targetElement.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' })
    }
  }
  e.preventDefault()
}
// 更新HTML内容
const updateHTML = (html: string) => {
  if (html !== internalValue.value) {
    internalValue.value = html
    emit('update:modelValue', html)
    emit('change', html)
  }
}
// 图片上传
const imageUpload = ({ file, callback }) => {
  let imageUrl
  const uploadFileLost = async (file) => {
    if (file) {
      const data = new FormData()
      data.append('file', file)
      data.append('parentPath', '/notice/')
      const result = await uploadFile(data)
      if (result.success && result.data.url) {
        imageUrl = result.data.url
      }
    }
  }
  uploadFileLost(file)
  // 调用 callback，传入 imageUrl 即可实现图片渲染
  callback({
    code: 0,
    message: 'Upload success!',
    data: {
      imageUrl,
    },
  })
}
// 文件上传
const fileUpload = ({ file, callback }) => {
  let fileUrl
  const uploadFileLost = async (file) => {
    if (file) {
      const data = new FormData()
      data.append('file', file)
      data.append('parentPath', '/notice/')
      const result = await uploadFile(data)
      if (result.success && result.data.url) {
        fileUrl = result.data.url
      }
    }
  }
  uploadFileLost(file)
  // 调用 callback，传入 imageUrl 即可实现图片渲染
  callback({
    code: 0,
    message: 'Upload success!',
    fileUrl,
  })
}
const TOOLBAR_CONFIG = [
  ['undo', 'redo', 'clean', 'format-painter'],
  [
    // 请保留默认值为 false
    { header: [1, 2, 3, 4, 5, 6, false] },
    { font: [false, '仿宋_GB2312, 仿宋', '楷体', '隶书', '黑体', '无效字体, 隶书'] },
    { size: [false, '12px', '14px', '16px', '18px', '20px', '24px', '32px', '36px', '48px', '72px'] },
    { 'line-height': [false, '1.2', '1.5', '1.75', '2', '3', '4', '5'] },
  ],
  ['bold', 'italic', 'strike', 'underline', 'divider'],
  [{ color: [] }, { background: [] }],
  [{ align: '' }, { align: 'center' }, { align: 'right' }, { align: 'justify' }],
  [{ list: 'ordered' }, { list: 'bullet' }, { list: 'check' }],
  [{ script: 'sub' }, { script: 'super' }],
  [{ indent: '-1' }, { indent: '+1' }],
  [{ direction: 'rtl' }],
  ['link', 'blockquote', 'code', 'code-block'],
  ['image', 'file'],
  ['emoji', 'video', 'formula', 'screenshot', 'fullscreen'],
]

// 组件挂载时初始化
onMounted(() => {
  // 确保编辑器容器已渲染
  if (!editorRef.value) return
  FluentEditor.register({ 'modules/header-list': HeaderList }, true)

  // 实例化编辑器
  editorInstance = new FluentEditor(editorRef.value, {
    'theme': 'snow',
    'modules': {
      'image': {
        allowInvalid: true,
      },
      'counter': {
        // 输入长度
        count: props.maxLength,
      },
      // 工具栏
      'toolbar': TOOLBAR_CONFIG,
      // 开启文件上传功能
      'file': true,
      'header-list': {
        container: headerListRef.value,
      },
    },
    'header-list': {
      container: headerListRef.value,
      scrollContainer: window,
      topOffset: () => {
        const navOffset = document.querySelector('header.VPNav')?.getBoundingClientRect().height || 0
        const VPOffset = document.querySelector('div.VPLocalNav')?.getBoundingClientRect().height || 0
        if (window.innerWidth <= 960) {
          return VPOffset
        } else if (window.innerWidth <= 1280) {
          return navOffset + VPOffset
        }
        return navOffset
      },
    },
    'uploadOption': {
      imageUpload, // 自定义图片上传方法
      fileUpload, // 自定义文件上传方法
    },
  })

  // 监听文本变化
  editorInstance.on('text-change', () => {
    if (editorInstance && editorInstance.root) {
      updateHTML(editorInstance.root.innerHTML)
    }
  })

  // 添加粘贴事件处理
  if (editorInstance.clipboard) {
    editorInstance.clipboard.addMatcher(Node.ELEMENT_NODE, handlePaste)
  }
  // 编辑器初始化完成后触发ready事件
  emit('ready', editorInstance)
})

// 监听外部值变化
watch(() => props.modelValue, (newValue) => {
  if (editorInstance && newValue !== internalValue.value) {
    // 更新内部状态
    internalValue.value = newValue
    // 设置编辑器内容
    editorInstance.root.innerHTML = newValue
  }
})

// 组件卸载时清理
onUnmounted(() => {
  if (editorInstance) {
    // 移除事件监听
    editorInstance.off('text-change')
    editorInstance = null
  }
})
</script>

<style scoped lang="scss">
.container {
  height: 100%;
  width: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}

.editor-container {
  height: 100%;
  display: flex;
  flex-direction: row;
  border: none !important;
}

#outline {
  display: flex;
  flex-direction: column;
  gap: 4px;

}

// 响应式设计
@media screen and (max-width: 1280px) {
  .directory-content {
    display: none;
    width: 15%;
  }
  .editor-main {
     flex: 1;
    width: 85%;
  }
}

@media screen and (max-width: 1400px) {
  .directory-content {
    width: 15%;
    min-width: 180px;
  }

  .editor-main {
     flex: 1;
    width: 85%;
  }
}
</style>
